package com.qf.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qf.device.Dto.DriverMqttDto;
import com.qf.device.entity.*;
import com.qf.device.mapper.*;
import com.qf.device.service.DeviceService;
import com.qf.device.util.MD5Util;
import com.qf.product.dto.PageDto;
import com.qf.product.entity.Product;
import com.qf.product.mapper.ProductMapper;
import com.qf.tenant.entity.Tenant;
import com.qf.vo.PageResult;
import com.qf.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * 设备表 服务实现类
 * </p>
 *
 * @author wxh
 * @since 2023-10-27
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private DeviceTypeMapper deviceTypeMapper;
    @Autowired
    private DeviceTopicMapper deviceTopicMapper;


    @Autowired
    private MqttUserMapper mqttUserMapper;

    @Autowired
    private MessageMapper messageMapper;


    /**
     * 设备分页
     * @param pageDto
     * @return
     */
    @Override
    public PageResult<Device> page(PageDto<Device> pageDto) {
        IPage<Device> page = new Page<>(pageDto.getNow(), pageDto.getSize());

        //判断where是否为空
        QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(pageDto.getWhere().getName())) {
            queryWrapper.lambda().eq(Device::getName, pageDto.getWhere().getName());
        }

        IPage<Device> pageInfo = this.baseMapper.selectPage(page, queryWrapper);

        //查询产品名称和控制设备名称
        for (Device record : pageInfo.getRecords()) {
            //查询产品名称
            Product product = productMapper.selectById(record.getProductId());
            //判断是否为空
            if (product != null) {
                record.setPname(product.getName());
            }
            //查询控制名称
            DeviceType deviceType = deviceTypeMapper.selectById(record.getDeviceTypeId());
            //判断是否为空
            if (deviceType != null){
                record.setTypeName(deviceType.getName());
            }

            //查询topic
            QueryWrapper<DeviceTopic> qw = new QueryWrapper<>();
            qw.lambda().eq(DeviceTopic::getDeviceKey,record.getDeviceKey());
            List<DeviceTopic> deviceTopics = deviceTopicMapper.selectList(qw);
            if (deviceTopics != null){
                record.setTopic(deviceTopics);
            }
        }

        PageResult pageResult = new PageResult();
        pageResult.setList(pageInfo.getRecords());
        pageResult.setTotal(pageInfo.getTotal());
        return pageResult;
    }

    @Override
    @Transactional
    public R<DriverMqttDto> auth(DriverMqttDto driverMqttDto) {
        log.info("开始认证...");
        if (driverMqttDto == null) {
            return R.fail(null,"非法参数");
        }
        //校验device
        QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Device::getDeviceKey,driverMqttDto.getDeviceKey())
                .eq(Device::getDeviceSecret,driverMqttDto.getDeviceSecret());
        Device device = this.baseMapper.selectOne(queryWrapper);
        if (device == null) {
            return R.fail(null,"非法设备");
        }
        log.info("[设备认证]合法设备：{}",device);
        device.setActive(2);
        this.baseMapper.updateById(device);

        //获取设备对应的租户对应的emqx账号（如果没有账号，生成账号）
        QueryWrapper<MqttUser>  mqttUserMapperQueryWrapper =
                new QueryWrapper<>();
        mqttUserMapperQueryWrapper.lambda().eq(MqttUser::getTenantId,device.getTenantId());
        MqttUser mqttUser = mqttUserMapper.selectOne(mqttUserMapperQueryWrapper);

        if (mqttUser == null) {
            //给租户添加emqx账号
            mqttUser = new MqttUser();
            mqttUser.setUsername(device.getDeviceKey());
            //把设备id前6位为mqttUser密码
            String substring = device.getId().substring(0, 6);
            mqttUser.setPassword(MD5Util.MD5Encode(substring));
            mqttUser.setCreated(new Date());
            mqttUser.setTenantId(device.getTenantId());
            mqttUserMapper.insert(mqttUser);

            log.info("[设备认证]给租户{}添加了账户{}",device.getTenantId(),mqttUser);
        }


        //获取设备的topic
        QueryWrapper<DeviceTopic> deviceTopicQueryWrapper =
                new QueryWrapper<>();
        deviceTopicQueryWrapper.lambda().eq(DeviceTopic::getDeviceKey,device.getDeviceKey());
        List<DeviceTopic> deviceTopics = deviceTopicMapper.selectList(deviceTopicQueryWrapper);
        List<DeviceTopic> data = deviceTopics.stream().filter(topic -> topic.getTopic().contains("data")).collect(Collectors.toList());
        //租户系统订阅数据上报的topic
        try {
            subTopic(data.get(0).getTopic(),mqttUser,device.getId());
            log.info("[设备认证]订阅topic成功{}",data.get(0).getTopic());
        } catch (Exception exception) {
            exception.printStackTrace();
            log.error("[设备认证]订阅topic失败{},账户信息{}",data.get(0).getTopic(),mqttUser);
        }


        //响应数据
        driverMqttDto.setUrl("tcp://47.110.143.177:1883");
        driverMqttDto.setIp("47.110.143.177");
        driverMqttDto.setPort(1883);
        driverMqttDto.setUsername(mqttUser.getUsername());
        driverMqttDto.setPassword(device.getId().substring(0,6));

        return R.ok(driverMqttDto,"auth success");
    }



    private void subTopic(String topic,MqttUser user,String deviceId) throws Exception{
        //1：实例化MqttClient
        String broker = "tcp://47.110.143.177:1883";
        String clientId = "zuhu";
        MemoryPersistence persistence = new MemoryPersistence();
        MqttClient client = new MqttClient(broker, clientId, persistence);


        //2： MQTT 连接选项
        MqttConnectOptions connOpts = new MqttConnectOptions();
        connOpts.setUserName(user.getUsername());
        connOpts.setPassword(deviceId.substring(0,6).toCharArray());
        // 保留会话
        connOpts.setCleanSession(true);

        //监听消息
        client.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable throwable) {

            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                Message message1 = new Message();
                message1.setTopic(topic);
                message1.setPayload(new String(message.getPayload()));
                messageMapper.insert(message1);
                System.out.println("topic="+topic);
                System.out.println("body="+new String(message.getPayload()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

            }
        });



        //3： 建立连接
        // 建立连接
        client.connect(connOpts);

        // 订阅
        client.subscribe(topic);

        log.info("{}订阅成功",topic);

    }





    @Override
    @Transactional
    public R insertDevice(Device device) {
        String idStr = IdWorker.getIdStr();
        device.setId(idStr);
        Tenant tenant = (Tenant) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        device.setTenantId(tenant.getId());
        device.setCreateTime(new Date());
        device.setUpdateTime(new Date());
        device.setDeleted(0);
        device.setActive(1);


        device.setDeviceKey("device_"+idStr);
        device.setDeviceSecret(MD5Util.MD5Encode(idStr));

        this.baseMapper.insert(device);


        //创建设备的两个topic（数据上报的topic以及发送指令topic）
        DeviceTopic dataTopic = new DeviceTopic();
        dataTopic.setTopic("/qfjava/device/data/"+device.getDeviceKey());
        dataTopic.setDeviceKey(device.getDeviceKey());
        dataTopic.setDeleted(0);
        dataTopic.setCreateTime(new Date());
        dataTopic.setUpdateTime(new Date());


        DeviceTopic cmdTopic = new DeviceTopic();
        cmdTopic.setTopic("/qfjava/device/ctrl/"+device.getDeviceKey());
        cmdTopic.setDeviceKey(device.getDeviceKey());
        cmdTopic.setDeleted(0);
        cmdTopic.setCreateTime(new Date());
        cmdTopic.setUpdateTime(new Date());

        deviceTopicMapper.insert(dataTopic);
        deviceTopicMapper.insert(cmdTopic);


        return R.ok("添加成功");


    }
}
